/*
 * Copyright (c) 2021 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * Mixin with profile-related helpers (for people and groups)
 */

import Log from './log.js';
import  {ensureTimestamp} from './utils.js';

var mergeModifiers = function mergeModifiers(data, modifiers) {
    Log.showInfo('mergeModifiers');
    if (modifiers) {
        if (modifiers.$ignoreAlias) {
            data.$ignoreAlias = modifiers.$ignoreAlias;
        }
        if (modifiers.$ignoreTime) {
            data.$ignoreTime = modifiers.$ignoreTime;
        }
        if (Object.prototype.hasOwnProperty.call(modifiers, '$ip')) {
            data.$ip = modifiers.$ip;
        }
        if (Object.prototype.hasOwnProperty.call(modifiers, '$time')) {
            data.$time = ensureTimestamp(modifiers.$time);
        }
        if (Object.prototype.hasOwnProperty.call(modifiers, '$latitude') &&
        Object.prototype.hasOwnProperty.call(modifiers, '$longitude')) {
            data.$latitude = modifiers.$latitude;
            data.$longitude = modifiers.$longitude;
        }
    }
    return data;
};

var ProfileHelpers = (Base = Object) => class extends Base {
    get token() {
        return this.mixpanel.token;
    }

    get config() {
        return this.mixpanel.config;
    }

    _set(prop, to, modifiers, callback, {identifiers, setOnce = false}) {
        Log.showInfo('ProfileHelpers _set');
        let $set = {};

        if (typeof (prop) === 'object') {
            if (typeof (to) === 'object') {
                callback = modifiers;
                modifiers = to;
            } else {
                callback = to;
            }
            $set = prop;
        } else {
            $set[prop] = to;
            if (typeof (modifiers) === 'function' || !modifiers) {
                callback = modifiers;
            }
        }

        let data = {
            '$token': this.token,
            ...identifiers,
        };

        const setKey = setOnce ? '$setOnce' : '$set';
        data[setKey] = $set;

        if ('ip' in $set) {
            data.$ip = $set.ip;
            delete $set.ip;
        }

        if ($set.$ignoreTime) {
            data.$ignoreTime = $set.$ignoreTime;
            delete $set.$ignoreTime;
        }

        data = mergeModifiers(data, modifiers);

        if (this.config.debug) {
            Log.showInfo(`Sending the following data to Mixpanel (${this.endpoint}):`);
            Log.showInfo(data);
        }

        this.mixpanel.sendRequest({ method: 'GET', endpoint: this.endpoint, data }, callback);
    }

    _deleteProfile({identifiers, modifiers, callback}) {
        Log.showInfo('ProfileHelpers _deleteProfile');
        let data = {
            '$delete': '',
            '$token': this.token,
            ...identifiers,
        };

        if (typeof (modifiers) === 'function') {
            callback = modifiers;
        }

        data = mergeModifiers(data, modifiers);

        if (this.config.debug) {
            Log.showInfo(`Deleting profile ${JSON.stringify(identifiers)}`);
        }

        this.mixpanel.sendRequest({ method: 'GET', endpoint: this.endpoint, data }, callback);
    }

    _remove({identifiers, data, modifiers, callback}) {
        Log.showInfo('ProfileHelpers _remove');
        let $remove = {};

        if (typeof (data) !== 'object' || Array.isArray(data)) {
            if (this.config.debug) {
                Log.showError('Invalid value passed to #remove - data must be an object with scalar values');
            }
            return;
        }

        for (const key in data) {
            if (Object.prototype.hasOwnProperty.call(data, key)) {
                const val = data[key];
                if (typeof (val) === 'string' || typeof (val) === 'number') {
                    $remove[key] = val;
                } else {
                    if (this.config.debug) {
                        Log.showError('Invalid argument passed to #remove - values must be scalar');
                        Log.showError('Passed ' + key + ':', val);
                    }
                    return;
                }
            }
        }

        if (Object.keys($remove).length === 0) {
            return;
        }

        data = {
            '$remove': $remove,
            '$token': this.token,
            ...identifiers
        };

        if (typeof (modifiers) === 'function') {
            callback = modifiers;
        }

        data = mergeModifiers(data, modifiers);

        if (this.config.debug) {
            Log.showInfo(`Sending the following data to Mixpanel (${this.endpoint}):`);
            Log.showInfo(data);
        }

        this.mixpanel.sendRequest({ method: 'GET', endpoint: this.endpoint, data }, callback);
    }

    _union({identifiers, data, modifiers, callback}) {
        Log.showInfo('ProfileHelpers _union');
        let $union = {};

        if (typeof (data) !== 'object' || Array.isArray(data)) {
            if (this.config.debug) {
                Log.showError('Invalid value passed to #union - data must be an object with scalar or array values');
            }
            return;
        }

        for (const key in data) {
            if (Object.prototype.hasOwnProperty.call(data, key)) {
                const val = data[key];
                if (Array.isArray(val)) {
                    var mergeValues = val.filter(function (v) {
                        return typeof (v) === 'string' || typeof (v) === 'number';
                    });
                    if (mergeValues.length > 0) {
                        $union[key] = mergeValues;
                    }
                } else if (typeof (val) === 'string' || typeof (val) === 'number') {
                    $union[key] = [val];
                } else {
                    if (this.config.debug) {
                        Log.showError('Invalid argument passed to #union - values must be a scalar value or array');
                        Log.showError('Passed ' + key + ':', val);
                    }
                }
            }
        }

        if (Object.keys($union).length === 0) {
            return;
        }

        data = {
            '$union': $union,
            '$token': this.token,
            ...identifiers,
        };

        if (typeof (modifiers) === 'function') {
            callback = modifiers;
        }

        data = mergeModifiers(data, modifiers);

        if (this.config.debug) {
            Log.showInfo(`Sending the following data to Mixpanel (${this.endpoint}):`);
            Log.showInfo(data);
        }

        this.mixpanel.sendRequest({ method: 'GET', endpoint: this.endpoint, data }, callback);
    }

    _unset({identifiers, prop, modifiers, callback}) {
        Log.showInfo('ProfileHelpers _unset');
        let $unset = [];

        if (Array.isArray(prop)) {
            $unset = prop;
        } else if (typeof (prop) === 'string') {
            $unset = [prop];
        } else {
            if (this.config.debug) {
                Log.showError('Invalid argument passed to #unset - must be a string or array');
                Log.showError('Passed: ' + prop);
            }
            return;
        }

        let data = {
            '$unset': $unset,
            '$token': this.token,
            ...identifiers,
        };

        if (typeof (modifiers) === 'function') {
            callback = modifiers;
        }

        data = mergeModifiers(data, modifiers);

        if (this.config.debug) {
            Log.showInfo(`Sending the following data to Mixpanel (${this.endpoint}):`);
            Log.showInfo(data);
        }

        this.mixpanel.sendRequest({ method: 'GET', endpoint: this.endpoint, data }, callback);
    }
};

export { ProfileHelpers, mergeModifiers };
